package com.hontech.bv.net.device

import com.hontech.bv.net.req.LoginReq
import com.hontech.bv.net.req.LoginRes
import com.hontech.bv.utils.SyncBox
import com.hontech.bv.utils.safeClose
import java.io.InputStream
import java.io.OutputStream
import java.net.InetSocketAddress
import java.net.Socket


class Client (host: String, port: Int) : Thread("client task") {

    companion object {

        const val TIMEOUT = 10 * 1000
    }

    private val socket = Socket()
    private val input: InputStream
    private val output: OutputStream
    val loginInfo: LoginRes
    private val box = SyncBox<Frame>()

    var connectFlag = true
        private set

    init {
        socket.connect(InetSocketAddress(host, port), TIMEOUT)
        socket.soTimeout = TIMEOUT
        input = socket.getInputStream()
        output = socket.getOutputStream()

        output.writeJson(Proto.LOGIN, LoginReq())
        loginInfo = input.readJson(Proto.LOGIN)

        PollTask.start(this)
        start()
    }

    @Synchronized
    fun request(frame: Frame, timeout: Long): Frame {
        box.reset()
        write(frame)
        return box.get(timeout)
    }

    fun write(frame: Frame) {
        if (!connectFlag) {
            throw IllegalStateException("socket is close")
        }
        val buf = frame.build()
        output.write(buf)
    }

    @Synchronized
    fun close() {
        if (!connectFlag) {
            return
        }
        input.safeClose()
        output.safeClose()
        socket.safeClose()
        connectFlag = false
        TcpMod.reconnect()
    }

    override fun run() {
        while (true) {
            try {
                runOnce()
            } catch (e: Exception) {
                e.printStackTrace()
                break
            }
        }
        close()
    }

    private fun runOnce() {
        val frame = input.readFrame()
        when (frame.req) {
            Proto.POLL -> {
                box.put(frame)
            }

        }
    }


}


